use std::vec::Vec;

use sea_orm::DatabaseConnection;
use uuid::Uuid;
use key_management::api::{CryptoOperations, DefaultCryptoImpl};

use crate::entities::{policy::Policy, signature_policy::SignaturePolicy};
use crate::policy_error::policy_error::PolicyError;
use crate::repositories::policy_repository::PolicyRepository;
use crate::util::policy_util::PolicyUtil;

pub struct QueryPolicyHandler;

impl QueryPolicyHandler {
    pub async fn get_policies_by_ids(
        db: &DatabaseConnection,
        policy_ids: Vec<String>,
    ) -> Result<Vec<Policy>, PolicyError> {
        let uuids: Result<Vec<Uuid>, _> = policy_ids.iter().map(|id| uuid::Uuid::parse_str(id)).collect();

        let uuids = match uuids {
            Ok(ids) => ids,
            Err(e) => return Err(PolicyError::IncorrectFormatError(e.to_string())),
        };

        let signature_policies = match PolicyRepository::get_correct_policies_by_ids(&db, uuids).await {
            Ok(policies) => policies,
            Err(e) => return Err(PolicyError::DatabaseOperationError(e.to_string())),
        };

        if signature_policies.is_empty() {
            return Ok(Vec::new());
        }

        let verified_policies = Self::verify_signature_policies(signature_policies, &db).await.unwrap();
        Ok(verified_policies.into_iter().map(Policy::from).collect())
    }

    pub async fn get_default_policies_by_type(
        db: &DatabaseConnection,
        attester_type: String,
    ) -> Result<Vec<Policy>, PolicyError> {
        let signature_policies = match PolicyRepository::get_default_policies_by_type(db, attester_type).await {
            Ok(policies) => policies,
            Err(e) => return Err(PolicyError::DatabaseOperationError(e.to_string())),
        };

        if signature_policies.is_empty() {
            return Ok(Vec::new());
        }

        let verified_policies = Self::verify_signature_policies(signature_policies, &db).await.unwrap();
        Ok(verified_policies.into_iter().map(Policy::from).collect())
    }

    async fn verify_signature_policies(signature_policies: Vec<SignaturePolicy>, db: &DatabaseConnection) -> Result<Vec<SignaturePolicy>, PolicyError> {
        let is_require_sign = PolicyUtil::get_bool_yaml_config("attestation_service.attestation_verifier.is_require_sign", false);
        let mut correct_signature_policies = Vec::new();
        if is_require_sign {
            let crypto_ops = DefaultCryptoImpl;
            for policy in signature_policies.iter() {
                let data = policy.encode_to_bytes();
                match crypto_ops.verify("FSK", Some(&policy.key_version), data, policy.signature.clone()).await {
                    Ok(true) => correct_signature_policies.push(policy.clone()),
                    Ok(false) => {
                        PolicyRepository::set_is_corrupted_use_connection(&db, policy.policy_id).await?;
                    },
                    Err(e) => {
                        return Err(PolicyError::PolicySignatureVerificationError(e.to_string()))
                    }
                }
            }
        } else {
            correct_signature_policies = signature_policies.clone();
        }

        Ok(correct_signature_policies)
    }
}